feat: pre-compress frontend assets at build time#6497
Conversation
Generate gzip/brotli/zstd sidecars during `reflex export` and serve the best match via a new PrecompressedStaticFiles handler. Adds a configurable `frontend_compression_formats` (defaults to gzip) and switches the prod test harness off the stdlib http.server in favor of the same Starlette/Uvicorn stack used in production so the precompressed path is exercised under integration tests.
Greptile SummaryThis PR adds build-time pre-compression of frontend static assets (gzip, brotli, zstd) via a new Node.js script (
Confidence Score: 4/5Core compression and serving logic is correct; the main risk area is the test harness rewrite, not the feature itself. The PrecompressedStaticFiles handler and compression pipeline are well-structured and thoroughly tested. The AppHarnessProd rewrite reads uvicorn's internal .servers[0].sockets to discover the bound port and mutates the process-global config.deploy_url β neither breaks the feature itself, but both add fragility to the test harness that could surface as confusing failures on a uvicorn upgrade or in long pytest sessions. reflex/testing.py β the uvicorn internals access and global config mutation deserve a second look before this pattern is copied elsewhere in the test suite. Important Files Changed
Sequence DiagramsequenceDiagram
participant Dev as Developer
participant Build as build.py
participant JS as compress-static.js
participant Server as PrecompressedStaticFiles
participant Browser as Browser
Dev->>Build: reflex export
Build->>JS: node compress-static.js static_dir gzip brotli zstd
JS->>JS: Walk files matching COMPRESSIBLE_EXTENSIONS
JS->>JS: Write .gz .br .zst sidecars for each file
Browser->>Server: GET /assets/app.js with Accept-Encoding br,gzip
Server->>Server: _parse_accept_encoding header
Server->>Server: _select_sidecar picks best quality on disk
Server-->>Browser: 200 Content-Encoding br Vary Accept-Encoding
Browser->>Server: GET /missing-route
Server->>Server: super get_response returns FileResponse 404.html
Server->>Server: Intercept and re-route through file_response
Server-->>Browser: 404 Content-Encoding br compressed 404.html
|
|
Nice! |
masenf
left a comment
There was a problem hiding this comment.
Some benchies on the docs app: uv run reflex run --env prod
Default compression ["gzip"]
Compiling: ββββββββββββββββββββββββββββββββββββββββ 100% 866/865 0:02:11
Creating Production Build: ββββββββββββββββββββββββββββββββββββββ 100% 4/4 0:02:07
["brotli", "zstd"]
Compiling: ββββββββββββββββββββββββββββββββββββββββ 100% 866/865 0:02:14
Creating Production Build: ββββββββββββββββββββββββββββββββββββββββ 100% 4/4 0:02:12
["brotli"]
Compiling: ββββββββββββββββββββββββββββββββββββββββ 100% 866/865 0:02:30
Creating Production Build: ββββββββββββββββββββββββββββββββββββββββ 100% 4/4 0:02:22
main
Compiling: ββββββββββββββββββββββββββββββββββββββββ 100% 866/865 0:02:24
Creating Production Build: ββββββββββββββββββββββββββββββββββββββββ 100% 4/4 0:02:24
masenf
left a comment
There was a problem hiding this comment.
This is good to go for me, but as a follow up PR, it would be nice to tighten up the progress bar. As it is now, a large site that has a lot to compress will just kind of sit there and it's not clear what it's waiting for.
I'll spec out some other tickets, but as part of the opentel stuff, we need to switch over to using python logging and use traces for calculating timing, etc.
Generate gzip/brotli/zstd sidecars during
reflex exportand serve the best match via a new PrecompressedStaticFiles handler. Adds a configurablefrontend_compression_formats(defaults to gzip) and switches the prod test harness off the stdlib http.server in favor of the same Starlette/Uvicorn stack used in production so the precompressed path is exercised under integration tests.All Submissions:
Type of change
Please delete options that are not relevant.
New Feature Submission:
Changes To Core Features: